package com.example.hello.views.assignments;

import com.example.hello.*;
import com.example.hello.POJO.AssignmentPOJO;
import com.example.hello.POJO.TrackPOJO;
import com.example.hello.POJO.UserPOJO;
import com.example.hello.views.tracks.Track;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.Users;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;

public class Assignments extends VerticalLayout implements View {

    public static final String NAME = "assignments";

    private static UserPOJO currentUser;
    private static List<AssignmentPOJO> assignments = new LinkedList<>();

    private VerticalLayout addLayout = new VerticalLayout();
    private HorizontalLayout viewLayout = new HorizontalLayout();

    private HorizontalLayout add = new HorizontalLayout();
    private VerticalLayout description = new VerticalLayout();
    private BootstrapButton view = new BootstrapButton("View", BootstrapButton.Size.SMALL);
    private BootstrapButton delete = new BootstrapButton("Delete", BootstrapButton.Size.SMALL);

    private StringWrap selectedAssignment;

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        assignments = GETAssignments("");
//        if (assignments == null) assignments = new LinkedList<>();

        add.setVisible(currentUser.isSiteAdmin());
        delete.setVisible(currentUser.isSiteAdmin());
        if (currentUser.isSiteAdmin()) {
            view.setWidth("110px");
        } else {
            view.setWidth("220px");
        }

        /** Redirect to Assignment View if needed **/
        String[] parameters = event.getParameters().split("/");
        if (!parameters[0].equals("")) {
            AssignmentPOJO assignment = Assignment.GETAssignment(parameters[0]);
            if (assignment != null) {
                Assignment assignmentView = new Assignment(Assignments.NAME + "/" + assignment.getEncodedName(), assignment);
                getUI().getNavigator().addView(assignmentView.NAME, assignmentView);
                getUI().getNavigator().navigateTo(assignmentView.NAME);
            } else {
                getUI().getNavigator().navigateTo(NAME);
            }
        }
    }

    public Assignments() {
        setWidth("100%");
        selectedAssignment = new StringWrap();

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        assignments = GETAssignments("");
        if (assignments == null) assignments = new LinkedList<>();
        
        initAdd();
        initDisplay();

        addComponent(addLayout);
        addComponent(viewLayout);
        setComponentAlignment(viewLayout, Alignment.TOP_CENTER);
        setExpandRatio(viewLayout, 1);
    }
    
    private void initAdd() {
        add.setWidth("800px");

        final Heading nameHeading = new Heading("Name", 6);
        final TextField nameField = new TextField();
        final Heading trackHeading = new Heading("Track", 6);
        final TextField trackField = new TextField();
        trackField.setWidth("100%");
        final Heading descriptionHeading = new Heading("Description", 6);
        final TextArea descriptionField = new TextArea();
        descriptionField.setWidth("220px");
        descriptionField.setHeight("162px");
        final Heading submissionPointsHeading = new Heading("Submission Points", 6);
        final TextField submissionPointsField = new TextField();
        submissionPointsField.setWidth("50px");
        final Heading reviewPointsHeading = new Heading("Review Points", 6);
        final TextField reviewPointsField = new TextField();
        reviewPointsField.setWidth("50px");
        final BootstrapButton assignmentSubmit = new BootstrapButton("Add Assignment");
        assignmentSubmit.setWidth("120px");

        assignmentSubmit.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                AssignmentPOJO assignment = new AssignmentPOJO(
                        nameField.getEncodedValue(),
                        descriptionField.getValue(),
                        NAME.split("/")[1],
                        new ArrayList<String>(),
                        Integer.valueOf(submissionPointsField.getValue()),
                        Integer.valueOf(reviewPointsField.getValue())
                );
                Track.addAssignment(
                        Track.GETTrack(trackField.getEncodedValue()),
                        assignment,
                        true
                );
                getUI().getNavigator().navigateTo(Assignments.NAME);
            }
        });
        TextField.enterKeyHandler(assignmentSubmit, nameField);
        TextField.enterKeyHandler(assignmentSubmit, descriptionField);
        TextField.enterKeyHandler(assignmentSubmit, submissionPointsField);
        TextField.enterKeyHandler(assignmentSubmit, reviewPointsField);

        add = new HorizontalLayout(
                nameHeading, new HSpacer(5), nameField,
                new HSpacer(20),
                submissionPointsHeading, new HSpacer(5), submissionPointsField,
                new HSpacer(20),
                reviewPointsHeading, new HSpacer(5), reviewPointsField,
                new HSpacer(20),
                assignmentSubmit
        );

        add.setComponentAlignment(nameHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(nameField, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(submissionPointsHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(submissionPointsField, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(reviewPointsHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(reviewPointsField, Alignment.MIDDLE_LEFT);
        add.setExpandRatio(nameField, 1);

        addLayout.addComponents(new VSpacer(10), add, new VSpacer(20));
        addLayout.setComponentAlignment(add, Alignment.MIDDLE_CENTER);

//        description.addComponent(new HSpacer(40));
        description.addComponent(trackHeading);
        description.addComponent(trackField);
        description.addComponent(descriptionHeading);
        description.addComponent(descriptionField);
        description.setWidth("220px");
        description.setHeight("256px");
        description.setComponentAlignment(descriptionHeading, Alignment.MIDDLE_LEFT);
        description.setComponentAlignment(descriptionField, Alignment.MIDDLE_LEFT);
        description.setExpandRatio(descriptionField, 1);
    }
    
    private void initDisplay() {
        final ListBox assignmentList = new ListBox();
        delete.setWidth("110px");

        assignmentList.setVisibleItems(16);
        for (AssignmentPOJO assignment : assignments) assignmentList.addItem(assignment.getDecodedName());
        Collections.sort(assignmentList.getItems());
        if (assignmentList.getItems().size() != 0) {
            selectedAssignment.setString(assignmentList.getItems().get(0));
        } else {
            view.setEnabled(false);
            delete.setEnabled(false);
        }
        assignmentList.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                if (event instanceof ListBoxChangeEvent) selectedAssignment.setString(((ListBoxChangeEvent) event).getSelected());
            }
        });
        view.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                getUI().getNavigator().navigateTo(NAME + "/" + selectedAssignment.getEncoded());
            }
        });
        delete.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                removeAssignment(Assignment.GETAssignment(selectedAssignment.getEncoded()));
                getUI().getNavigator().navigateTo(NAME);
            }
        });

        HorizontalLayout buttons = new HorizontalLayout(view, delete);

        VerticalLayout tmp = new VerticalLayout(assignmentList, buttons);
        tmp.setComponentAlignment(assignmentList, Alignment.TOP_CENTER);
        tmp.setComponentAlignment(buttons, Alignment.TOP_CENTER);

        // add assignmentList for display
        viewLayout.addComponent(tmp);
        viewLayout.addComponent(new HSpacer(40));
        viewLayout.addComponent(description);
    }

    public static List<AssignmentPOJO> GETAssignments(String query) {
        List<AssignmentPOJO> assignments = new LinkedList<>();
        try {
            String json = HttpRequest.GET(Assignments.NAME + query);
            ObjectMapper mapper = new ObjectMapper();
            assignments = mapper.readValue(json, new TypeReference<List<AssignmentPOJO>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return assignments;
    }

    public static List<AssignmentPOJO> getAssignments() {
        return assignments;
    }

    public static void setAssignments(List<AssignmentPOJO> assignments) {
        Assignments.assignments = assignments;
    }

    public static boolean addAssignment(AssignmentPOJO assignment) {
        // post a assignment to get an _id
        if (!HttpRequest.executePost(NAME, assignment.toJSON())) return false;

        // get the assignment with _id attached
        assignment = Assignment.GETAssignment(assignment.getEncodedName());
        if (!assignments.contains(assignment)) assignments.add(assignment);

        // create the View with the assignment
        Assignment assignmentView = new Assignment(Assignments.NAME + "/" + assignment.getEncodedName(), assignment);
        HelloUI.getCurrent().getNavigator().addView(assignmentView.NAME, assignmentView);

        return true;
    }

    public static boolean removeAssignment(AssignmentPOJO assignment) {
        // get all linked resources and update or relocate
        Set<TrackPOJO> tracks = Tracks.GETTracks("?assignment=" + assignment);
        Set<UserPOJO> users = Users.GETUsers("?assignment=" + assignment);
        for (TrackPOJO track : tracks) {
            if (track.removeAssignment(assignment.getEncodedName())) track.update();
        }
        for (UserPOJO user : users) {
            if (user.removeAssignment(assignment.getEncodedName())) user.update();
        }

        // delete the assignment
        HttpRequest.executeDelete(NAME + "/" + assignment.getEncodedName());
        HelloUI.getCurrent().getNavigator().removeView(NAME + "/" + assignment.getEncodedName());

        return assignments.remove(assignment);
    }

    public static boolean hasAssignment(AssignmentPOJO assignment) {
        return assignments.contains(assignment);
    }

}